package com.dongrj.framework.core.utils;


import com.dongrj.framework.core.Pid;
import com.dongrj.framework.core.Snowflake;
import com.dongrj.framework.core.exception.Assert;
import com.dongrj.framework.core.exception.SystemException;
import com.dongrj.framework.core.instance.InstanceFactory;

/**
 * ID生成器工具类，此工具类中主要封装：
 *
 * <pre>
 * 1. 唯一性ID生成器：UUID、ObjectId（MongoDB）、Snowflake
 * </pre>
 *
 * <p>
 * ID相关文章见：http://calvin1978.blogcn.com/articles/uuid.html
 *
 * @author looly
 * @since 4.1.13
 */
public class IdUtils {

    public static long nextNo() {
        Snowflake instance = InstanceFactory.getInstance(Snowflake.class, Snowflake::new);
        return instance.nextId();
    }

    /**
     * 获取数据中心ID<br>
     * 数据中心ID依赖于本地网卡MAC地址。
     * <p>
     * 此算法来自于mybatis-plus#Sequence
     * </p>
     *
     * @param maxDataCenterId 最大的中心ID
     * @return 数据中心ID
     * @since 5.7.3
     */
    public static long getDataCenterId(long maxDataCenterId) {
        Assert.isTrue(maxDataCenterId > 0, "maxDataCenterId must be > 0");
        if (maxDataCenterId == Long.MAX_VALUE) {
            maxDataCenterId -= 1;
        }
        long id = 1L;
        byte[] mac = null;
        try {
            mac = NetUtils.getLocalHardwareAddress();
        } catch (SystemException ignore) {
            // ignore
        }
        if (null != mac) {
            id = ((0x000000FF & (long) mac[mac.length - 2])
                    | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;
            id = id % (maxDataCenterId + 1);
        }

        return id;
    }

    /**
     * 获取机器ID，使用进程ID配合数据中心ID生成<br>
     * 机器依赖于本进程ID或进程名的Hash值。
     *
     * <p>
     * 此算法来自于mybatis-plus#Sequence
     * </p>
     *
     * @param dataCenterId 数据中心ID
     * @param maxWorkerId  最大的机器节点ID
     * @return ID
     * @since 5.7.3
     */
    public static long getWorkerId(long dataCenterId, long maxWorkerId) {
        final StringBuilder mpid = new StringBuilder();
        mpid.append(dataCenterId);
        try {
            mpid.append(Pid.INSTANCE.get());
        } catch (SystemException igonre) {
            //ignore
        }
        /*
         * MAC + PID 的 hashcode 获取16个低位
         */
        return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
    }
}
